﻿using FFmpeg.NET;
using FFmpeg.NET.Enums;
using System;
using System.Diagnostics;
using System.IO;
using System.Threading.Tasks;

namespace Coldairarrow.Util.VideoConvert
{
    public  class VideoConverts
    {
        public static string ffmpegtool = @"\ffmpeg\ffmpeg.exe"; 
        public static string mp4fragmenttool = @"\Bento4\mp4fragment.exe";
        public static async Task VideoStartConvert(VideoModel input,string rootPath)
        {
            MediaFile inputFile = new MediaFile(@input.InputPath);
            //以路径为参数创建文件
            //File.Create(@input.OutputPath);
            MediaFile outputFile = new MediaFile(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @input.OutputPath));

            Engine ffmpeg = new Engine(rootPath + ffmpegtool);

            var metadata = await ffmpeg.GetMetaDataAsync(inputFile);

            ConversionOptions conversionOptions = new ConversionOptions
            {
                MaxVideoDuration = TimeSpan.FromSeconds(30),
                VideoAspectRatio = VideoAspectRatio.Default,
                VideoSize = VideoSize.Default,
                AudioSampleRate = AudioSampleRate.Hz44100
            };

            //string options = $"ffmpeg -i {input.InputPath} -g 52 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov {@input.OutputPath}";
          


            var data = await ffmpeg.ConvertAsync(inputFile, outputFile, conversionOptions);
            File.Delete(@input.InputPath);
        }

        public static void ConvertVideo(VideoModel input,int type)
        {
            Process p = new Process();//建立外部调用线程
            p.StartInfo.FileName = ffmpegtool;//要调用外部程序的绝对路径
                                              //参数(这里就是FFMPEG的参数了)
                                              //p.StartInfo.Arguments = @"-i "+sourceFile+ " -ab 56  -b a -ar 44100 -b 500 -r 29.97 -s 1280x720 -y " + playFile+"";

            // p.StartInfo.Arguments = "-y -i \""+sourceFile+"\" -b v   -s 800x600 -r 29.97 -b 1500 -acodec aac -ac 2 -ar 24000 -ab 128 -vol 200 -f psp  \""+playFile+"\" ";


            //string strArg = "-i " + sourceFile + " -y -s 640x480 " + playFile + " ";
            //string strArg = "-i " + input.InputPath + " -vcodec h264 " + input.OutputPath + " ";
            //string strArg = "-i " + input.InputPath + " -vcodec h264 " + input.OutputPath + " ";
            string strArg = "-i " + input.InputPath + " -an -vcodec libx264 -crf 23 " + input.OutputPath + " ";
            if (type == 1)
            {
                strArg = "-i " + input.InputPath + " -g 52 -vcodec copy -f mp4 -movflags frag_keyframe+empty_moov " + input.OutputPath + " ";
            }

            //获取图片
            //截取图片jpg
            //string strArg = "-i " + sourceFile + " -y -f image2 -t 1 " + imgFile;
            //string strArg = "-i " + sourceFile + " -y -s 1280x720 -f image2 -t 1 " + imgFile;

            //视频截取
            //string strArg = "  -i " + sourceFile + " -y   -ss 0:20  -frames 100  " + playFile;

            //转化gif动画
            //string strArg = "-i " + sourceFile + " -y -s 1280x720 -f gif -vframes 30 " + imgFile;
            //string strArg = "  -i " + sourceFile + " -y  -f gif -vframes 50 " + imgFile;
            // string strArg = "  -i " + sourceFile + " -y  -f gif -ss 0:20  -dframes 10 -frames 50 " + imgFile;

            //显示基本信息
            //string strArg = "-i " + sourceFile + " -n OUTPUT";

            //播放视频 
            //string strArg = "-stats -i " + sourceFile + " ";

            p.StartInfo.Arguments = strArg;

            p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
            p.StartInfo.CreateNoWindow = false;//不创建进程窗口
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            p.Start();//启动线程
            p.BeginErrorReadLine();//开始异步读取
            p.WaitForExit();//阻塞等待进程结束
            p.Close();//关闭进程
            p.Dispose();//释放资源
            File.Delete(@input.InputPath);
        }

        public static void ConvertVideoToM3u8(VideoModel input, string rootPath)
        {
            Serilog.Log.Information("--------进入m3u8格式转换----------");
            Serilog.Log.Information("input.InputPath： " + input.InputPath);
            Serilog.Log.Information("input.OutputPath： " + input.OutputPath);
            Process p = new Process();//建立外部调用线程
            p.StartInfo.FileName =  rootPath + ffmpegtool;//要调用外部程序的绝对路径
                                              //参数(这里就是FFMPEG的参数了)
            //string strArg = " -hide_banner  -i " + input.InputPath + " -c:v libx264 -crf 30 -c:a aac -strict -2 -f hls -hls_time 3 -hls_list_size 8000 " + input.OutputPath + " ";

            string strArg = " -hide_banner -i " + input.InputPath + " -c:v libx264 -crf 28 -c:a aac -strict -2 -f hls  -hls_time 1 -hls_list_size 8000 " + input.OutputPath + " ";

            p.StartInfo.Arguments = strArg;

            p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
            p.StartInfo.CreateNoWindow = false;//不创建进程窗口
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            p.Start();//启动线程
            p.BeginErrorReadLine();//开始异步读取
            p.WaitForExit();//阻塞等待进程结束
            p.Close();//关闭进程
            p.Dispose();//释放资源

            Serilog.Log.Information("--------m3u8格式转换完成----------");
        }

        public static void ConvertFmp4Video(VideoModel input, string rootPath)
        {
            Process p = new Process();//建立外部调用线程
            p.StartInfo.FileName = rootPath + mp4fragmenttool;//要调用外部程序的绝对路径

            string strArg = " " + input.InputPath + " " + input.OutputPath + " ";

            p.StartInfo.Arguments = strArg;

            p.StartInfo.UseShellExecute = false;//不使用操作系统外壳程序启动线程(一定为FALSE,详细的请看MSDN)
            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流,用StandardOutput是捕获不到任何消息的...这是我耗费了2个多月得出来的经验...mencoder就是用standardOutput来捕获的)
            p.StartInfo.CreateNoWindow = false;//不创建进程窗口
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN
            p.Start();//启动线程
            p.BeginErrorReadLine();//开始异步读取
            p.WaitForExit();//阻塞等待进程结束
            p.Close();//关闭进程
            p.Dispose();//释放资源
        }

        private static void Output(object sendProcess, DataReceivedEventArgs output)
        {
            if (!String.IsNullOrEmpty(output.Data))
            {
                //处理方法...
                Console.WriteLine(output.Data);

                ////去获取时长
                //string partitio1 = @"Duration: \d{2}:\d{2}:\d{2}.\d{2}";
                //if (RegexHelper.IsMatch(partitio1, output.Data))
                //{
                //    string partition = @"(?<=Duration: )\d{2}:\d{2}:\d{2}.\d{2}";
                //    string timespan = RegexHelper.Matchs(output.Data, partition).FirstOrDefault();
                //    TimeSpan span;
                //    if (TimeSpan.TryParse(timespan, out span))
                //    {
                //        Console.WriteLine(span.TotalMilliseconds);
                //    }
                //}

                ////获取时刻
                //string partitio2 = @"time=\d{2}:\d{2}:\d{2}.\d{2}";
                //if (RegexHelper.IsMatch(partitio2, output.Data))
                //{
                //    string partition = @"(?<=time=)\d{2}:\d{2}:\d{2}.\d{2}";

                //    string timespan = RegexHelper.Matchs(output.Data, partition).FirstOrDefault();
                //    TimeSpan span;
                //    if (TimeSpan.TryParse(timespan, out span))
                //    {
                //        Console.WriteLine(span.TotalMilliseconds);
                //    }
                //}
            }
        }
    }
}
